package com.example.concurrentprogramming8016.synchronizedLearn;


import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicStampedReference;
import java.util.concurrent.atomic.LongAdder;

/**
 * @author liyanhao
 * @Date 2023-01-04 14:17
 */
public class SyncDemo {
    private static volatile int counter = 0;
    //解决并发问题方法1  AtomicInteger
    private static AtomicInteger counter2 = new AtomicInteger(0);
    //优化解决并发问题 方法 2 LongAdder
    private static LongAdder count3 = new LongAdder();
    //优化解决并发问题 方法3 AtomicIntegerFieldUpdater
    volatile int count4 = 0;
    private static final AtomicIntegerFieldUpdater atomicIntegerFieldUpdaterCount4 =
            AtomicIntegerFieldUpdater.newUpdater(SyncDemo.class, "count4");
    //优化解决并发问题 方法4 AtomicStampedReference 解决ABA问题 虽然此问题不存在版本号问题
    private static AtomicStampedReference<Integer> atomicStampedReferenceCount5
            = new AtomicStampedReference<>(0, 0);


    public static void decrement() {
        counter--;
        counter2.decrementAndGet();
        count3.decrement();

        int stamp = atomicStampedReferenceCount5.getStamp();
        Integer reference = atomicStampedReferenceCount5.getReference();
        boolean b = atomicStampedReferenceCount5.compareAndSet(reference, reference - 1, stamp, stamp + 1);
        while (!b) {
            stamp = atomicStampedReferenceCount5.getStamp();
            reference = atomicStampedReferenceCount5.getReference();
            b = atomicStampedReferenceCount5.compareAndSet(reference, reference - 1, stamp, stamp + 1);
        }
    }

    public static void increment() {
        counter++;
        counter2.incrementAndGet();
        count3.increment();
        int stamp = atomicStampedReferenceCount5.getStamp();
        Integer reference = atomicStampedReferenceCount5.getReference();
        boolean b = atomicStampedReferenceCount5.compareAndSet(reference, reference + 1, stamp, stamp + 1);
        while (!b) {
            stamp = atomicStampedReferenceCount5.getStamp();
            reference = atomicStampedReferenceCount5.getReference();
            b = atomicStampedReferenceCount5.compareAndSet(reference, reference + 1, stamp, stamp + 1);
        }
    }

    public static void decrement2(SyncDemo syncDemo) {
//        counter--;
//        count3.decrement();
        atomicIntegerFieldUpdaterCount4.decrementAndGet(syncDemo);
    }

    public static void increment2(SyncDemo syncDemo) {
//        counter++;
//        count3.increment();
        atomicIntegerFieldUpdaterCount4.incrementAndGet(syncDemo);
    }


    public static void main(String[] args) throws InterruptedException {
        SyncDemo syncDemo = new SyncDemo();
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 5001; i++) {
                increment2(syncDemo);
                increment();
            }
        });
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                decrement2(syncDemo);
                decrement();
            }
        });
        thread.start();
        thread1.start();
        thread.join();
        thread1.join();
        System.out.println("counter1=" + counter);
        System.out.println("counter2=" + counter2);
        System.out.println("counter3=" + count3);
        System.out.println("counter4=" + atomicIntegerFieldUpdaterCount4.get(syncDemo));
        System.out.println("counter5=" + atomicStampedReferenceCount5.getReference());
        System.out.println("count5-stamp=" + atomicStampedReferenceCount5.getStamp());

    }
}